﻿function Dragdroper(config) {
    var _this = this; var EmptyFunction = function () {
    };
    function $e(obj) {
        return obj === undefined || typeof (obj) === undefined || obj === null || obj === "";
    };
    function setDefaultConfig(config) {
        if ($e(config)) config = {
        };
        if ($e(config.multiDragdrop))
            config.multiDragdrop = false;
        if ($e(config.innerDragdrop))
            config.innerDragdrop = false;
        if ($e(config.useHoverColor))
            config.useHoverColor = false;
        if ($e(config.removeSource))
            config.removeSource = false;
        if ($e(config.dragSource)) {
            var error = "必须指定拖放源！dragSource";
            alert(error);
            throw {
                message: error
            };
        };
        if ($e(config.dropTarget)) {
            if (config.innerDragdrop) {
                config.dropTarget = config.dragSource;
            } else {
                config.dropTarget = null;
            }
        };
        if ($e(config.isAcceptableSource))
            config.isAcceptableSource = isAcceptableSource;
        if ($e(config.isAcceptableTarget))
            config.isAcceptableTarget = isAcceptableTarget;
        if ($e(config.acceptCursor))
            config.acceptCursor = "move";
        if ($e(config.forbidenCursor))
            config.forbidenCursor = "";
        if ($e(config.beginDragdrop))
            config.beginDragdrop = EmptyFunction;
        if ($e(config.endDragdrop))
            config.endDragdrop = EmptyFunction;
        if ($e(config.dropItemChanged))
            config.dropItemChanged = EmptyFunction;
        if ($e(config.createDragItem))
            config.createDragItem = createDragItem;
        if ($e(config.hoverTargetBgcolor))
            config.hoverTargetBgcolor = "Transparent";
        return config;
    };
    function isAcceptableSource(dragdroper, dragSource) {
        if (config.multiDragdrop) {
            for (var i in config.dragSource) {
                if (dragdroper.isChild(dragSource, config.dragSource[i])) {
                    return true;
                }
            };
            return false;
        } else {
            return dragdroper.isChild(dragSource, config.dragSource);
        }
    };
    function isAcceptableTarget(dragdroper, dropTarget) {
        if (config.multiDragdrop) {
            for (var i in config.dropTarget) {
                if (dropTarget === config.dropTarget[i] || dragdroper.isChild(dropTarget, config.dropTarget[i])) {
                    return true;
                }
            };
            return false;
        } else {
            if (dropTarget === config.dropTarget) {
                return true;
            };
            return dragdroper.isChild(dropTarget, config.dropTarget);
        }
    };
    function createDragItem(dragdroper) {
        var result = document.createElement("div");
        result.innerHTML = dragdroper.dragedItem.outerHTML; with (result.style) {
            border = "1px solid SkyBlue";
            backgroundColor = "#EEEEEE";
            filter = "Alpha(Opacity=60)";
            padding = 3;
            zIndex = 999999;
            position = "absolute";
        };
        result.firstChild.style.border = 0;
        return result;
    };

    function initMouseEvents(source) {
        var dragSourceCursor = null;
        var dragItemDisplay = null;
        var _overElement = null;
        var _bgcolor = null;
        var _mousedown = source.onmousedown || EmptyFunction;
        source.onmousedown = function (event) {
            var event = event || window.event;
            var eventSrc = event.target || event.srcElement;
            if (event.button === 0 || event.button === 1) {
                if (config.isAcceptableSource(_this, eventSrc)) {
                    _this.dragedItem = eventSrc;
                    config.beginDragdrop(_this, _this.dragedItem);
                    dragdropItem = null;

                    if (!window.captureEvents) {
                        source.setCapture();
                    } else {
                        window.captureEvents(Event.MOUSEMOVE | Event.MOUSEUP);
                    }

                    if (source.style.cursor) {
                        dragSourceCursor = source.style.cursor;
                    } else {
                        dragSourceCursor = "";
                    }
                }
            };
            _mousedown();
        };

        var _mouseup = source.onmouseup || EmptyFunction;
        source.onmouseup = function () {
            if (_this.dragedItem) {
                try {
                    source.onmouseout();
                    _this.dragedItem.onmouseout();
                } catch (e) {
                };
                if (_this.dropedItem) {
                    _this.dragedItem.display = dragItemDisplay;
                    config.endDragdrop(_this, _this.dragedItem, _this.dropedItem);
                    config.dropItemChanged(_this, null, _this.dropedItem);
                    if (config.removeSource) {
                        var tmp = _this.dragedItem.parentNode;
                        tmp.removeChild(_this.dragedItem);
                    }
                };
                if (_this.dragdropItem) {
                    var tmp = _this.dragdropItem.parentNode;
                    tmp.removeChild(_this.dragdropItem);
                    _this.dragdropItem = null;
                };

                _this.dragedItem = null;
                _this.dropedItem = null;
                source.style.cursor = dragSourceCursor;

                if (!window.captureEvents) {
                    source.releaseCapture();
                } else {
                    window.releaseEvents(Event.MOUSEMOVE | Event.MOUSEUP);
                }
            };
            _mouseup();
        };

        var _mousemove = source.onmousemove || EmptyFunction;
        source.onmousemove = function (event) {
            var event = event || window.event;
            var eventSrc = event.target || event.srcElement;
            if (_this.dragedItem) {
                if (_this.dragdropItem === null) {
                    _this.dragdropItem = config.createDragItem(_this);
                    document.body.appendChild(_this.dragdropItem);
                    dragItemDisplay = _this.dragdropItem.style.display;
                    if (config.removeSource) {
                        _this.dragdropItem.style.display = "none";
                    }
                };
                var maxX = document.body.clientWidth - 20;
                var maxY = document.body.clientHeight - 20;

                _this.dragdropItem.style.left = 10 + (event.x < 0 ? 0 : event.x < maxX ? event.x : maxX) + "px";
                _this.dragdropItem.style.top = 5 + (event.y < 0 ? 0 : event.y < maxY ? event.y : maxY) + "px";

                var _old = _this.dropedItem;
                _this.dropedItem = null;
                if (!config.innerDragdrop && (eventSrc === source || config.isAcceptableSource(_this, eventSrc))) {
                    source.style.cursor = dragSourceCursor;
                } else if (config.isAcceptableTarget(_this, eventSrc)) {
                    source.style.cursor = config.acceptCursor;
                    if (eventSrc !== _this.dragedItem) {
                        _this.dropedItem = eventSrc;
                    } else {
                        _this.dropedItem = null;
                    };
                    _this.dropedItem = eventSrc;
                } else {
                    source.style.cursor = config.forbidenCursor;
                };
                if (_old !== _this.dropedItem) {
                    config.dropItemChanged(_this, _this.dropedItem, _old);
                }
            };
            _mousemove();
            return _this.dragedItem ? false : true;
        };
        if (config.useHoverColor) {
            var _mouseover = source.onmouseover || EmptyFunction;
            source.onmouseover = function (event) {
                var event = event || window.event;
                var eventSrc = event.target || event.srcElement;
                if (isAcceptableTarget(_this, eventSrc)) {
                    _overElement = eventSrc;
                    _bgcolor = _overElement.style.backgroundColor;
                    _overElement.style.backgroundColor = config.hoverTargetBgcolor;
                };
                _mouseover();
            };
            var _mouseout = source.onmouseout || EmptyFunction;
            source.onmouseout = function () {
                if (_overElement !== null) {
                    _overElement.style.backgroundColor = _bgcolor;
                    _overElement = null;
                }
            };
        }
    };
    function initDragdroper() {
        config = setDefaultConfig(config);
        var sources = config.dragSource;
        if (!config.multiDragdrop) {
            sources = [sources];
        };
        for (var i = 0; i < sources.length; i++) {
            initMouseEvents(sources[i]);
        }
    };
    {
        initDragdroper();
    };
    this.dragedItem = null;
    this.dropedItem = null;
    this.dragdropItem = null;
    this.getConfig = function () {
        return config;
    };
    this.getDragSource = function () {
        return config.dragSource;
    };
    this.getdropTarget = function () {
        return config.dropTarget;
    };
    this.isChild = function (node, parentNode) {
        return parentNode.contains(node);
    };
    this.defaultIsAcceptableSource = isAcceptableSource;
    this.defaultIsAcceptableTarget = isAcceptableTarget;
    this.defaultCreateDragItem = createDragItem;
}